package com.xiaoman.jvm.classpath;

import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

public class Classpath {
    /**
     * 启动类路径
     */
    private Entry bootstrapClasspath;
    /**
     * 扩展类路径
     */
    private Entry extensionClasspath;
    /**
     * 用户类路径
     */
    private Entry userClasspath;

    /**
     * 构造函数
     * @param jreOption jre路径
     * @param cpOption 用户路径
     */
    public Classpath(String jreOption, String cpOption)
    {
        parseBootAndExtClasspath(jreOption);
        parseUserClasspath(cpOption);
    }

    /**
     * 解析用户类路径
     *
     * @param cpOption
     */
    private void parseUserClasspath(String cpOption) {
        if (StringUtils.isBlank("."))
            cpOption = ".";
        userClasspath = Entry.newEntry(cpOption);
    }

    /**
     * 解析启动类和扩展类路径
     *
     * @param jreOption
     */
    private void parseBootAndExtClasspath(String jreOption) {
        String jreDir = getJreDir(jreOption);
        // ..jre/lib/*
        String jreLibPath = Paths.get(jreDir, "lib") + Entry.pathListSeparator + "*";
        bootstrapClasspath = Entry.newEntry(jreLibPath);
        //..jre/lib/ext/*
        String jreExtPath = Paths.get(jreDir, "lib", "ext") + Entry.pathListSeparator + "*";
        extensionClasspath = Entry.newEntry(jreExtPath);

    }

    /**
     * 优先使用用户输入的-Xjre选项作为jre目录。如果没有输入该选项，则在当前目录下寻找jre目录。如果找不到，尝试使用JAVA_HOME环境变量
     *
     * @param jreOption
     */
    private String getJreDir(String jreOption) {
        if (StringUtils.isNotBlank(jreOption) && Files.exists(Paths.get(jreOption)))
            return jreOption;
        if (Files.exists(Paths.get("./jre")))
            return "./jre";
        String jh = System.getenv("JAVA_HOME");
        if (StringUtils.isNotBlank(jh))
            return Paths.get(jh, "jre").toString();
        throw new RuntimeException("Can not find jre folder!");
    }

    /**
     * 依次从启动类路径、扩展类路径和用户类路径中搜索class文件
     *
     * @param className 类名称
     * @return
     */
    public byte[] readClass(String className) throws IOException {
        className = className + ".class";

        //[readClass]启动类路径
        try {
            return bootstrapClasspath.readClass(className);
        } catch (Exception ignored) {
            //ignored
        }

        //[readClass]扩展类路径
        try {
            return extensionClasspath.readClass(className);
        } catch (Exception ignored) {
            //ignored
        }

        //[readClass]用户类路径
        return userClasspath.readClass(className);
    }


}
